package com.runa.monitor.platinterface.extend.flightControl;

import com.alibaba.fastjson.JSON;
import com.rn.smart.command.dto.valve.ValveBase;
import com.rn.smart.command.dto.valve.contro.FeiKongValve;
import com.runa.monitor.comm.dto.newComm.AsynResult;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.monitor.comm.entity.CommValve;
import com.runa.monitor.platinterface.mqtt.MqttUtil;
import com.runa.persistence.service.CommValveService;
import com.runa.rccprotocol.flightControl.*;
import com.runa.rccprotocol.http.HttpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 2024/9/6 10:02
 * zhangYB
 */
@Slf4j
@Service
public class FlightControlService {

    @Resource
    private HttpService httpService;

    @Value("${flight.control.username:}")
    private String username;
    @Value("${flight.control.password:}")
    private String password;
    @Value("${flight.control.loginUrl:}")
    private String loginUrl;
    @Value("${flight.control.valveOpeningControlUrl:}")
    private String valveOpeningControlUrl;
    @Value("${flight.control.valveOutTemperatureControlUrl:}")
    private String valveOutTemperatureControlUrl;

    private LoginResponse loginResponse;

    @Resource
    private CommValveService commValveService;

    public void send(FlightControl flightControl) {
        try {
            ControlTask controlTask = flightControl.getControlTask();
            log.debug("controlTask: {}", JSON.toJSONString(controlTask));
            if (null == loginResponse || !loginResponse.isSuccess() || loginResponse.expired()) {
                if (!login()) {
                    return;
                }
            }
            String authorization = loginResponse.getAuthorization();
            log.debug("飞控Token: {}", authorization);
            ResponseEntity responseEntity = httpService.exchange(controlTask.getUrl(), controlTask.getHttpMethod()
                    , controlTask.getRequest(), controlTask.getResponseType(), authorization);
            log.debug("飞控请求结果: {}", JSON.toJSONString(responseEntity));
            HttpStatus httpStatus = responseEntity.getStatusCode();
            if (httpStatus.is2xxSuccessful()) {
                Object body = responseEntity.getBody();
                if (body instanceof Response) {
                    Response response = (Response)body;
                    if (!response.isSuccess()) {
                        log.error("飞控请求失败: {} {} {}", JSON.toJSONString(controlTask), authorization, JSON.toJSONString(responseEntity));
                        if (response.getCode() == 401 && response.getMessage().contains("尚未登录")) {
                            login();
                        }
                        return;
                    }
                    log.debug("飞控请求成功: {} {} {}", JSON.toJSONString(controlTask), authorization, JSON.toJSONString(responseEntity));
                    AsynResult asynResult = AsynResult.success();
                    asynResult.setIdentity(flightControl.getCommValve().getId());
                    asynResult.setTask(controlTask.getTask());
                    asynResult.setHoldInfo(controlTask.getHoldInfo());
                    asynResult.setTimestamp(System.currentTimeMillis());
                    MqttUtil.send(MqttUtil.topicOfNoneContentForNode, asynResult);
                }
            } else {
                log.error("飞控阀控失败: {} {}", JSON.toJSONString(controlTask), JSON.toJSONString(httpStatus));
            }
        } catch (Exception e) {
            log.error("", e);
        }
    }

    public void sendTemperatureControl(List<FeiKongValve> feiKongValves, String task, String holdInfo, Integer priority, String url, HttpMethod httpMethod) {
        Map<String, CommValve> commValveMap = batchQueryValve(task, holdInfo, feiKongValves);
        for (FeiKongValve feiKongValve : feiKongValves) {
            CommValve commValve = commValveMap.get(feiKongValve.getValveAddress());
            if (null == commValve) {
                continue;
            }
            ValveOutTemperatureControlRequest requestBody = ValveOutTemperatureControlRequest.getRequestBody(feiKongValve, commValve);
            ControlTask controlTask = new ControlTask(task, holdInfo, priority, url, httpMethod, requestBody, Response.class);
            FlightControl flightControl = new FlightControl(commValve, controlTask);
            send(flightControl);
        }
    }

    public void sendValveControl(List<FeiKongValve> feiKongValves, String task, String holdInfo, Integer priority, String url, HttpMethod httpMethod) {
        Map<String, CommValve> commValveMap = batchQueryValve(task, holdInfo, feiKongValves);
        for (FeiKongValve feiKongValve : feiKongValves) {
            CommValve commValve = commValveMap.get(feiKongValve.getValveAddress());
            if (null == commValve) {
                continue;
            }
            ValveOpeningControlRequest requestBody = ValveOpeningControlRequest.getRequestBody(feiKongValve, commValve);
            ControlTask controlTask = new ControlTask(task, holdInfo, priority, url, httpMethod, requestBody, Response.class);
            FlightControl flightControl = new FlightControl(commValve, controlTask);
            send(flightControl);
        }
    }

    public void send(List<ValveBase> valveBases, String task, String holdInfo, Integer priority) {
        Map<String, List<FeiKongValve>> typeMap = getTypeMap(valveBases);
        for (String type : typeMap.keySet()) {
            switch(type) {
                case "开度":
                    sendValveControl(typeMap.get(type), task, holdInfo, priority, valveOpeningControlUrl, HttpMethod.PUT);
                    break;
                case "回温":
                    sendTemperatureControl(typeMap.get(type), task, holdInfo, priority, valveOutTemperatureControlUrl, HttpMethod.PUT);
                    break;
            }

        }
    }


    public Map<String, CommValve> batchQueryValve(String taskNo, String holdInfo, List<FeiKongValve> feiKongValves) {
        ArrayList<String> nodeIds = new ArrayList<>(feiKongValves.stream().map(FeiKongValve::getValveAddress).distinct().collect(Collectors.toList()));
        List<CommValve> valves = commValveService.getAllByIds(nodeIds);

        List<String> valveIds = valves.stream().map(CommValve::getId).collect(Collectors.toList());
        for (String valveId : valveIds) {
            nodeIds.remove(valveId);
        }

        if (!nodeIds.isEmpty())
            nodeIds.forEach(s -> MqttUtil.sendOfWithoutArchive(taskNo, holdInfo, ValveVO.TOPIC, s));
        if (valves.isEmpty()) return new HashMap<>();

        return valves.stream().collect(Collectors.toMap(CommValve::getId, Function.identity()));
    }

    public Map<String, List<FeiKongValve>> getTypeMap(List<ValveBase> valveBases) {
        Map<String, List<FeiKongValve>> typeMap = new HashMap<>();
        for (ValveBase valveBase : valveBases) {
            if (!(valveBase instanceof FeiKongValve)) {
                log.error("飞控抄阀参数错误: {}", JSON.toJSONString(valveBase));
                continue;
            }
            FeiKongValve feiKongValve = (FeiKongValve)valveBase;
            List<FeiKongValve> feiKongValves = typeMap.get(feiKongValve.getType());
            if (null == feiKongValves) {
                feiKongValves = new ArrayList<>();
                typeMap.put(feiKongValve.getType(), feiKongValves);
            }
            feiKongValves.add(feiKongValve);
        }
        return typeMap;
    }

    public boolean login() {
        LoginRequest loginRequest = new LoginRequest(username, password);
        log.debug("飞控登录: {} {} {}", loginUrl, username, password);
        ResponseEntity<LoginResponse> responseEntity = httpService.post(loginUrl, loginRequest, LoginResponse.class);
        log.debug("飞控登录结果: {}", JSON.toJSONString(responseEntity));
        HttpStatus statusCode = responseEntity.getStatusCode();
        if (statusCode.is2xxSuccessful()) {
            this.loginResponse = responseEntity.getBody();
            this.loginResponse.setExpireTime(System.currentTimeMillis() + 1000 * 60 * 60 * 24);
            if (!this.loginResponse.isSuccess()) {
                log.error("飞控登录失败: {} {}", JSON.toJSONString(loginResponse));
                return false;
            }
        } else {
            this.loginResponse = new LoginResponse(statusCode.value(), statusCode.getReasonPhrase());
            return false;
        }
        return true;
    }



}
